/*
 * (c) ralfoide gmail com, 2008
 * Project: packer
 * License TBD
 */

package com.alfray.gamez.util;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.UserDataHandler;

public class NodesIteratorTest {
	
	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test(expected=NullPointerException.class)
	public void testNodesIterator_fromNull() {
		NodesIterator n = new NodesIterator(null);
		assertEquals(false, n.hasNext());
		n.next();
	}

	@Test(expected=IndexOutOfBoundsException.class)
	public void testNodesIterator_fromEmpty() {
		NodeList m = new MockNodeList(new MockNode[0]);
		NodesIterator n = new NodesIterator(m);
		assertEquals(false, n.hasNext());
		n.next();
	}

	@Test
	public void testHasNext() {
		MockNode n1 = new MockNode();
		NodeList m = new MockNodeList(new MockNode[] { n1 } );
		NodesIterator n = new NodesIterator(m);
		assertEquals(true, n.hasNext());
	}

	@Test
	public void testNext() {
		MockNode n1 = new MockNode();
		MockNode n2 = new MockNode();
		MockNode n3 = new MockNode();
		NodeList m = new MockNodeList(new MockNode[] { n1, n2, n3 } );
		NodesIterator n = new NodesIterator(m);

		assertEquals(0, n.getIndex());
		assertEquals(true, n.hasNext());
		assertSame(n1, n.next());
		
		assertEquals(1, n.getIndex());
		assertEquals(true, n.hasNext());
		assertSame(n2, n.next());
		
		assertEquals(2, n.getIndex());
		assertEquals(true, n.hasNext());
		assertSame(n3, n.next());
		
		assertEquals(3, n.getIndex());
		assertEquals(false, n.hasNext());
	}

	@Test(expected=UnsupportedOperationException.class)
	public void testRemove() {
		NodesIterator n = new NodesIterator(null);
		n.remove();
	}
	
	@Test
	public void testIterator() {
		Node[] result = new MockNode[3];
		int index = 0;
		
		MockNode n1 = new MockNode();
		MockNode n2 = new MockNode();
		MockNode n3 = new MockNode();
		NodeList m = new MockNodeList(new MockNode[] { n1, n2, n3 } );
		NodesIterator n = new NodesIterator(m);

		for (Node i : n) {
			result[index++] = i;
			assertEquals(index, n.getIndex());
		}
		
		assertArrayEquals(new Node[] { n1, n2, n3 }, result);
	}
	
	@Test
	public void testIterator_empty() {
		NodeList m = new MockNodeList(new MockNode[0] );
		NodesIterator n = new NodesIterator(m);

		for (@SuppressWarnings("unused") Node i : n) {
			throw new AssertionError("This should never get called.");
		}

		assertEquals(0, n.getIndex());
	}

	/** Iterating over null is safe */
	@Test
	public void testIterator_null() {
		NodesIterator n = new NodesIterator(null);

		for (@SuppressWarnings("unused") Node i : n) {
			throw new AssertionError("This should never get called.");
		}

		assertEquals(0, n.getIndex());
	}

	//----------------------------
	/** A trivial NodeList wrapping a Node array */
	private class MockNodeList implements NodeList {

		private final Node[] mNodeArray;

		public MockNodeList(Node[] nodeArray) {
			mNodeArray = nodeArray;
		}
		
		public int getLength() {
			return mNodeArray.length;
		}

		public Node item(int index) {
			return mNodeArray[index];
		}		
	}
	

	//----------------------------
	/** A trivial Node */
	private class MockNode implements Node {

		public Node appendChild(Node newChild) throws DOMException {
			// pass
			return null;
		}

		public Node cloneNode(boolean deep) {
			// pass
			return null;
		}

		public short compareDocumentPosition(Node other) throws DOMException {
			// pass
			return 0;
		}

		public NamedNodeMap getAttributes() {
			// pass
			return null;
		}

		public String getBaseURI() {
			// pass
			return null;
		}

		public NodeList getChildNodes() {
			// pass
			return null;
		}

		public Object getFeature(String feature, String version) {
			// pass
			return null;
		}

		public Node getFirstChild() {
			// pass
			return null;
		}

		public Node getLastChild() {
			// pass
			return null;
		}

		public String getLocalName() {
			// pass
			return null;
		}

		public String getNamespaceURI() {
			// pass
			return null;
		}

		public Node getNextSibling() {
			// pass
			return null;
		}

		public String getNodeName() {
			// pass
			return null;
		}

		public short getNodeType() {
			// pass
			return 0;
		}

		public String getNodeValue() throws DOMException {
			// pass
			return null;
		}

		public Document getOwnerDocument() {
			// pass
			return null;
		}

		public Node getParentNode() {
			// pass
			return null;
		}

		public String getPrefix() {
			// pass
			return null;
		}

		public Node getPreviousSibling() {
			// pass
			return null;
		}

		public String getTextContent() throws DOMException {
			// pass
			return null;
		}

		public Object getUserData(String key) {
			// pass
			return null;
		}

		public boolean hasAttributes() {
			// pass
			return false;
		}

		public boolean hasChildNodes() {
			// pass
			return false;
		}

		public Node insertBefore(Node newChild, Node refChild)
				throws DOMException {
			// pass
			return null;
		}

		public boolean isDefaultNamespace(String namespaceURI) {
			// pass
			return false;
		}

		public boolean isEqualNode(Node arg) {
			// pass
			return false;
		}

		public boolean isSameNode(Node other) {
			// pass
			return false;
		}

		public boolean isSupported(String feature, String version) {
			// pass
			return false;
		}

		public String lookupNamespaceURI(String prefix) {
			// pass
			return null;
		}

		public String lookupPrefix(String namespaceURI) {
			// pass
			return null;
		}

		public void normalize() {
			// pass
			
		}

		public Node removeChild(Node oldChild) throws DOMException {
			// pass
			return null;
		}

		public Node replaceChild(Node newChild, Node oldChild)
				throws DOMException {
			// pass
			return null;
		}

		public void setNodeValue(String nodeValue) throws DOMException {
			// pass
			
		}

		public void setPrefix(String prefix) throws DOMException {
			// pass
			
		}

		public void setTextContent(String textContent) throws DOMException {
			// pass
			
		}

		public Object setUserData(String key, Object data,
				UserDataHandler handler) {
			// pass
			return null;
		}
		
	}

}
